package com.yugao.fintech.antelope.auth.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yugao.fintech.antelope.auth.manager.LocalUserManager;
import com.yugao.fintech.antelope.auth.manager.ThirdUserManager;
import com.yugao.fintech.antelope.auth.mapper.LocalUserMapper;
import com.yugao.fintech.antelope.auth.model.CheckLoginParam;
import com.yugao.fintech.antelope.auth.model.entity.LocalUser;
import com.yugao.fintech.antelope.auth.model.entity.SocialUser;
import com.yugao.fintech.antelope.auth.model.rqrs.*;
import com.yugao.fintech.antelope.auth.service.LocalUserService;
import com.yugao.fintech.antelope.auth.service.OAuth2TokenService;
import com.yugao.fintech.antelope.base.security.utils.SecurityUtils;
import com.yugao.fintech.antelope.base.model.constants.AppType;
import com.yugao.fintech.antelope.base.model.constants.UserCons;
import com.yugao.fintech.framework.assistant.utils.CollectionUtils;
import com.yugao.fintech.framework.assistant.utils.RegexUtils;
import com.yugao.fintech.framework.assistant.utils.StringUtils;
import com.yugao.fintech.framework.assistant.utils.exception.Assert;
import com.yugao.fintech.framework.assistant.utils.exception.BizException;
import com.yugao.fintech.framework.core.utils.SpringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;
import java.util.Objects;


@Service
public class LocalUserServiceImpl extends ServiceImpl<LocalUserMapper, LocalUser> implements LocalUserService {
    @Autowired
    private OAuth2TokenService tokenService;
    @Autowired
    private ThirdUserManager thirdUserManager;

    public LocalUserServiceImpl(LocalUserManager localUserManager) {
    }

    @Override
    public LocalUser getUser(LocalUserGetReq req) {
        LambdaQueryWrapper<LocalUser> lqw = LocalUser.lqw();
        if (StringUtils.isNotEmpty(req.getAccount())) {
            String account = req.getAccount();
            if (RegexUtils.checkEmail(account)) {
                lqw.eq(LocalUser::getEmail, account).ge(LocalUser::getUserName, "").ge(LocalUser::getPhone, "");
            } else if (RegexUtils.checkPhone(account)) {
                lqw.ge(LocalUser::getEmail, "").ge(LocalUser::getUserName, "").eq(LocalUser::getPhone, account);
            } else {
                lqw.ge(LocalUser::getEmail, "").eq(LocalUser::getUserName, account).ge(LocalUser::getPhone, "");
            }
        }
        lqw.eq(LocalUser::getAppType, ObjectUtil.defaultIfNull(req.getAppType(), AppType.ADMIN_CONSOLE.getCode()));
        return this.getOne(lqw);
    }

    @Override
    public LocalUser getUserByUserId(Long userId) {
        if (Objects.isNull(userId)) {
            return null;
        }
        return this.getOne(LocalUser.lqw().eq(LocalUser::getUserId, userId));
    }

    @Override
    public boolean updateLocalUser(LocalUser req) {
        if (StringUtils.isNotEmpty(req.getPassword())) {
            req.setPassword(SecurityUtils.encryptPassword(req.getPassword()));
        }
        LambdaQueryWrapper<LocalUser> lqw = LocalUser.lqw().eq(LocalUser::getUserId, req.getUserId());
        checkRepeat(req, true);
        return this.update(req, lqw);
    }

    @Override
    @Transactional
    public void deleteLocalUser(Long userId) {
        boolean ret = this.remove(LocalUser.lqw().eq(LocalUser::getUserId, userId));
        if (!ret) {
            throw new BizException("注销用户失败");
        }
        // 删除第三方授权信息
        thirdUserManager.deleteAuthByUserId(userId);
    }

    @Override
    public void resetPassword(UserResetPwdReq req) {
        Long userId = SecurityUtils.getUserId();
        if (!req.getConfirmPassword().equals(req.getPassword())) {
            throw new BizException("两次输入新密码不一样!!");
        }

        LocalUser localUser = this.getUserByUserId(userId);
        if (localUser == null) {
            throw new BizException("用户不存在, 请联系管理员!!");
        }
        if (!SecurityUtils.matchesPassword(req.getOldPassword(), localUser.getPassword())) {
            throw new BizException("旧密码错误");
        }
        if (StringUtils.equals(req.getPassword(), req.getOldPassword())) {
            throw new BizException("新密码不能与旧密码相同");
        }
        tokenService.removeAccessTokenByUserId(userId);
        localUser.setPassword(req.getPassword());

        if (!this.updateLocalUser(localUser)) {
            throw new BizException("密码修改失败, 请联系管理员");
        }
    }

    @Override
    public boolean resetPassword(AdminResetPwdReq req) {
        if (!req.getConfirmPassword().equals(req.getPassword())) {
            throw new BizException("两次输入新密码不一样!!");
        }
        CheckLoginParam.of(null, req.getPassword()).passwordLength().throwError((errorEnum) -> {
            throw new BizException(errorEnum);
        });

        Long userId = req.getUserId();
        LocalUser localUser = new LocalUser();
        localUser.setUserId(userId);
        localUser.setPassword(req.getPassword());
        this.checkUserAllowed(localUser);

        LocalUser record = this.getUserByUserId(userId);
        if (record == null) {
            throw new BizException("用户不存在, 请联系管理员!!");
        }
        tokenService.removeAccessTokenByUserId(userId);
        return this.updateLocalUser(localUser);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDeleteLocalUser(Long tenantId, List<Long> userIds) {
        if (CollectionUtils.isEmpty(userIds)) {
            return;
        }
        this.remove(LocalUser.lqw().in(LocalUser::getUserId, userIds));
        // 删除第三方授权信息
        thirdUserManager.batchDeleteAuthByUserIds(userIds);
    }

    @Override
    @Transactional
    public void batchUpdateLocalUser(List<LocalUser> reqList) {
        if (CollectionUtils.isEmpty(reqList)) {
            return;
        }
        LocalUserServiceImpl proxy = SpringUtils.getAopProxy(this);
        for (LocalUser localUser : reqList) {
            proxy.updateLocalUser(localUser);
        }
    }

    @Override
    public void saveLocalUser(LocalUser req) {
        String encryptPassword = SecurityUtils.encryptPassword(req.getPassword());
        req.setPassword(encryptPassword);
        checkRepeat(req, false);
        this.save(req);
    }

    public void checkRepeat(LocalUser req, boolean isUpdate) {
        if (StringUtils.isAllEmpty(req.getEmail(), req.getUserName(), req.getPhone())) {
            return;
        }
        req.setAppType(StringUtils.defaultIfEmpty(req.getAppType(), AppType.APP.getCode()));
        LambdaQueryWrapper<LocalUser> lqw = LocalUser.lqw()
                .eq(LocalUser::getAppType, req.getAppType())
                .and(w -> w.eq(StringUtils.isNotEmpty(req.getUserName()), LocalUser::getUserName, req.getUserName())
                        .or(StringUtils.isNotEmpty(req.getEmail()))
                        .eq(StringUtils.isNotEmpty(req.getEmail()), LocalUser::getEmail, req.getEmail())
                        .or(StringUtils.isNotEmpty(req.getPhone()))
                        .eq(StringUtils.isNotEmpty(req.getPhone()), LocalUser::getPhone, req.getPhone()))
                .ne(isUpdate, LocalUser::getUserId, req.getUserId())
                .ne(LocalUser::getStatus, UserCons.Status.DELETED);

        LocalUser auth = this.getOne(lqw);
        if (Objects.nonNull(auth)) {
            Assert.isFalse(checkField(auth.getUserName(), req.getUserName()), new BizException("用户名已存在"));
            Assert.isFalse(checkField(auth.getEmail(), req.getEmail()), new BizException("邮箱已存在"));
            Assert.isFalse(checkField(auth.getPhone(), req.getPhone()), new BizException("手机号已存在"));
        }
    }

    public boolean checkField(String data1, String data2) {
        return !StringUtils.isAllEmpty(data1, data2) && StringUtils.equals(data1, data2);
    }

    public void checkUserAllowed(LocalUser auth) {
        if (StringUtils.isNotNull(auth.getUserId()) && auth.isAdmin()) {
            throw new BizException("不允许操作超级管理员用户");
        }
    }

    @Override
    public List<LocalUser> listAuth(LocalUserListReq query) {
        if (CollectionUtils.isEmpty(query.getUserIds())) {
            return Collections.emptyList();
        }
        LambdaQueryWrapper<LocalUser> lqw = LocalUser.lqw().in(LocalUser::getUserId, query.getUserIds());
        return this.list(lqw);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelAccount(CancelAccountReq req) {
        LambdaQueryWrapper<LocalUser> lqw = LocalUser.lqw()
                .eq(LocalUser::getUserId, req.getUserId())
                .eq(LocalUser::getAppType, req.getAppType());
        this.remove(lqw);

        LambdaQueryWrapper<SocialUser> thirdUserLqw = SocialUser.lqw()
                .eq(SocialUser::getUserId, req.getUserId());
        this.thirdUserManager.remove(thirdUserLqw);
    }
}
